{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modGIDtoSTR;

interface

uses Classes, modClassElements, modBaseType,
     sFonctionsChaines, SysUtils;


const
   CNT_GID_VAISSEAUX_RECYCLEUR = 209;
   CNT_GID_VAISSEAUX_SONDES    = 210;


   CNT_GID_VAISSEAUX_PETIT_TRANSPORTEUR    = 202;
   CNT_GID_VAISSEAUX_GRAND_TRANSPORTEUR    = 203;

const
    // On exploite le GID dans les liens
    CNT_BATIMENT_METAL            = 1;
    CNT_BATIMENT_CRISTAL          = 2;
    CNT_BATIMENT_DEUT             = 3;
    CNT_BATIMENT_CENTRALE_SOLAIRE = 4;
    CNT_BATIMENT_CENTRALE_FUSION  = 12;
    CNT_BATIMENT_USINEROBOT       = 14;
    CNT_BATIMENT_USINENANITE      = 15;
    CNT_BATIMENT_CHANTIERSPACIAL  = 21;
    CNT_BATIMENT_STOCK_METAL      = 22;
    CNT_BATIMENT_STOCK_CRISTAL    = 23;
    CNT_BATIMENT_STOCK_DEUT       = 24;
    CNT_BATIMENT_LABORATOIRE      = 31;
    CNT_BATIMENT_SILOMISSILES     = 44;

    CNT_TECHNO_ESPIONAGE            = 106;
    CNT_TECHNO_ORDINATEUR           = 108;
    CNT_TECHNO_ARMES                = 109;
    CNT_TECHNO_BOUCLIER             = 110;
    CNT_TECHNO_PROTECTION           = 111;
    CNT_TECHNO_ENERGIE              = 113;
    CNT_TECHNO_HYPERESPACE          = 114;
    CNT_TECHNO_COMBUSTIONINTERNE    = 115;
    CNT_TECHNO_REACTEURIMPULSION    = 117;
    CNT_TECHNO_PROPULSIONHYPERESPACE = 118;
    CNT_TECHNO_LASER                = 120;
    CNT_TECHNO_IONS                 = 121;
    CNT_TECHNO_PLASMA               = 122;
    CNT_TECHNO_GRAVITON             = 199;


    CNT_VAISSEAUX_SAT_SOLAIRE = 212;




type
    TGIDtoSTR = record
       GID: integer;
       Valeur: string;
    end;


    PGIDtoSTR = ^TGIDtoSTR;
    TCollectionGIDtoSTR = class(TList)
    private
       {--------------------------------------------------}
       {Elements spécialisés de la classes}
       FFichier: string;

       // Sert pour le rapport d'espionnage si jamais l'élément n'est
       // pas trouvé
       FAllowAjoutAutoFromStrWithRandomID: boolean;
      
       {--------------------------------------------------}
       {Gestion des pointeurs}
       // Utilisé pour la propriété Itemx
       function GetItemx(Index: integer): TGIDtoSTR;
    public
       property FichierSave: string read FFichier write FFichier;


       function GetMaxLengthStr: integer;

       {--------------------------------------------------}
       {Gestion des pointeurs}
       // *** Ajout de pointeurs
       // Renvoi le pointeur de l'élément ajouté
       function Add(Element: TGIDtoSTR): PGIDtoSTR;
      
       // Simple ajout de pointeur
       procedure SimpleAdd(Pointeur: PGIDtoSTR);
      
       // Renvoi le pointeur de l'élément ajouté/modifié
       // Utilise Get_Index pour vérifier si l'élément doit être mis à jour
       function Add_Update(Element: TGIDtoSTR): PGIDtoSTR;
      
      
       // *** Suppression de pointeur
       // Libère et supprime le pointeur Index
       // Renvoi True si réussit, False si hors limite ou erreur
       function Delete(Index: integer): boolean;

      
       // *** Effacement de la liste de pointeur
       procedure Clear; override;
      
      
       // *** Requete sur la liste de pointeur
       function Get_Index(Element: integer): integer;
       function Get_Pointeur(Element: integer): PGIDtoSTR;
       function Get_Item(Index: integer): TGIDtoSTR;
       property Itemx[Index: integer]: TGIDtoSTR read GetItemx;


       // Pour le trie des éléments
       procedure Trie;

      
       {--------------------------------------------------}
       {Procédures et fonctions spécialisées de la classes}
       // Destructeur
       destructor Destroy; override;
       constructor Create;
       
       function SaveToFile(Fichier: string = ''): integer;
       function LoadFromFile(Fichier: string = ''): integer;

       function UpdateFromListElement(List: TListElements): integer;
       function GetGIDStr(GID: integer): string;

       // Sert pour les rapports d'espionnage
       function GetGIDFromStr(str: string): integer;

       
       // renvoi le nombre d'élément d'un même type
       // cela sert pour connaitre le nombre de vaisseaux existant
       function GetNbElementOfThisType(GidType: integer): integer;
    end;


    
implementation



{*******************************************************************************
 ******************************************************************************* 
 **               TCollectionGIDtoSTR                                     **
 *******************************************************************************
 *******************************************************************************}


function TCollectionGIDtoSTR.GetNbElementOfThisType(GidType: integer): integer;
var i: integer;
    e: PGIDtoSTR;
begin
    Result := 0;

    if Count = 0 then exit;


    for i := 0 to Count - 1 do begin
        e := Items[i];

        if GetTypeOfGID(e.GID) = GidType then begin
           Inc(Result);
        end;

    end;

end;

function TCollectionGIDtoSTR.GetMaxLengthStr: integer;
var i: integer;
    e: PGIDtoSTR;
begin
    Result := 0;

    if Count = 0 then exit;

    for i := 0 to Count - 1 do begin
        e := Items[i];

        if length(e.Valeur) > Result then begin
           if GetTypeOfGID(e.GID) <> CNT_ITEM_DESIGN_RECHERCHE then
              Result := length(e.Valeur);

        end;

    end;

end;

function TCollectionGIDtoSTR.GetGIDFromStr(str: string): integer;
label NotFound;
var i: integer;
    e: PGIDtoSTR;
begin

    // La fonction appellante doit prendre le soin d'effacer les espaces
    // dans la chaine

    if Count = 0 then goto NotFound;

    for i := 0 to Count - 1 do begin
        e := Items[i];

        if SameText(str, e.Valeur) then begin
           Result := e.GID;
           exit;
        end;

    end;


NotFound:
    if FAllowAjoutAutoFromStrWithRandomID then begin
       // L'élément n'a pas été trouvé, mais on peut lui associer un id aléatoire
       // NON GERE POUR L'INSTANT (à ne jamais gérer d'ailleurs)
       Result := -1;
    end else begin
       Result := -1;
    end;


end;


function TCollectionGIDtoSTR.GetGIDStr(GID: integer): string;
var plElement: PGIDtoSTR;
begin
    Result := '';

    plElement := Get_Pointeur(GID);

    if plElement = nil then begin
       Result := IntToStr(GID);
       exit;
    end;

    Result := plElement.Valeur;
end;

function TCollectionGIDtoSTR.UpdateFromListElement(List: TListElements): integer;
var cElement: POGItemCost;
    plElement: PGIDtoSTR;
    aElement: TGIDtoSTR;
    i, k: integer;
begin

    Result := -1;
    if List.Count = 0 then exit;

    k := 0;

    for i := 0 to List.Count - 1 do begin
        cElement := List.Items[i];

        plElement := Get_Pointeur(cElement.GID);

        if plElement = nil then begin
           aElement.GID := cElement.GID;
           aElement.Valeur := cElement.Nom;
           Add(aElement);
           Inc(k);
        end;

    end;


    Result := k;

end;

function TCollectionGIDtoSTR.LoadFromFile(Fichier: string): integer;
var Element: TGIDtoSTR;
    F: TextFile;
    Ligne, s: string;
    xPos, id: integer;
begin


    if Fichier = '' then Fichier := FFIchier;
    
    // ATTENTION: Les éléments sont effacés avant le chargement, à modifier en fonction de ce que l'on veut
    Clear;
    
    Result  := 0;
    Fichier := sfcUnixPathToDosPath(Fichier);
    FFichier := Fichier;
    if FileExists(Fichier) = false then exit;
    
    
    AssignFile(F, FFichier);


    {$I-}
    ReSet(F);
    {$I+}

    // IOResult renvoie 0 => cela signifie que la dernière opération d'E/S a réussi
    if NoT(IOResult = 0) then begin
       Result := -1;
       exit;
    end;
    
    While NoT(EoF(F)) do begin
         // Lit une ligne
         ReadLn(F, Ligne);
         
         if Ligne = '' then Continue;
         if Ligne[1] = '/' then Continue;
         if Ligne[1] = '#' then Continue;

         xPos := pos('=', Ligne);
         if xPos = 0 then continue;

         s := copy(Ligne, 1, xPos - 1);


         try
            id := StrToInt(s);
         except
            s := '';
            id := 0;
         end;

         if s <> '' then begin
            System.Delete(Ligne, 1, xPos);

            Ligne := trim(Ligne);

            if Ligne <> '' then begin
               Element.GID := id;
               Element.Valeur := Ligne;

               Add(Element);

            end;

         end;

    end;
    
    // Fermeture du fichier
    CloseFile(F);
    
end;


function TCollectionGIDtoSTR.SaveToFile(Fichier: string): integer;
var i: integer;
    F: TextFile;
    pElement: PGIDtoSTR;
begin

    Result := -2;

    if Fichier = '' then Fichier := FFichier;
    
    AssignFile(F, Fichier);
    
    {$I-}
    ReWrite(F);
    {$I+}
    
    // IOResult renvoie 0 => cela signifie que la dernière opération d'E/S a réussi
    if NoT(IOResult = 0) then begin
       Result := -1;
       exit;
    end;

    Trie;
    
    for i := 0 to Count - 1 do begin
        pElement := Items[i];
        
        //
        // Ecriture ici
        //
        WriteLn(F, format('%d=%s', [pElement.GID, pElement.Valeur]));

    end;
    
    // Résultat
    Result := Count;
    
    // Ferme le fichier
    CloseFile(F);
    
end;

constructor TCollectionGIDtoSTR.Create;
begin
    
    // Héritage
    InHerited Create;
    
    
    
    // Code pour l'initialisation ici
    
    
end;

destructor TCollectionGIDtoSTR.Destroy;
begin
    // Implémenter le code avant l'héritage de la méthode
    // C'est à dire ici
    
   
    // On appelle NOTRE clear qui lui-même appelle NOTRE Delete qui libère l'espace mémoire
    // avant d'enlever le pointeur de la TList
    // L'héritage de Destroy appelle Clear, mais es-ce le notre ou celui de la classe de base ?
    Clear;
    
    
    // Héritage
    InHerited Destroy;
end;

// ATTENTION: Ce n'est pas une méthode de classe, sinon ça ne marche pas
function CompareElementsPGIDtoSTR(Item1, Item2: Pointer): Integer;
var e1, e2: PGIDtoSTR;
begin


    // Compare renvoie < 0 si Item1 est inférieur à Item2,
    //                   0 s'ils sont égaux
    //                 > 0 si Item1 est supérieur à Item2
    // Voir http://alphomega.developpez.com/TriTList/
    // pour savoir comment trier sur plusieurs critére

    e1 := Item1;
    e2 := Item2;

    // Ici on ne compare que deux entiers, donc:
    if e1.GID < e2.GID then
       // Item1 est inférieur à Item2
       Result := -1

    else if e1.GID = e2.GID then
       // Egalité
       Result := 0

    else
       // Sinon Item1 est supérieur à Item2
       Result := 1;

end;


procedure TCollectionGIDtoSTR.Trie;
begin
    Sort(CompareElementsPGIDtoSTR);
end;


procedure TCollectionGIDtoSTR.Clear;
var i: integer;
begin

    if Count > 0 then begin
        For i := Count -1 downto 0 do
            Delete(i);
    end;
    
    inherited Clear;
end;


function TCollectionGIDtoSTR.Get_Pointeur(Element: integer): PGIDtoSTR;
var i: integer;
begin

   Result := nil;
   
   i := Get_Index(Element);
   if i < 0 then exit;
   Result := Items[i];

end;


function TCollectionGIDtoSTR.Get_Index(Element: integer): integer;
var i: integer;
    pElement: PGIDtoSTR;
begin

   Result := -1;

   if Count <= 0 then exit;

   for i := 0 to Count - 1 do begin
      pElement := Items[i];

      {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
      {### Neccessite adpation en fonction du type record  ### }
      {### ### ### ### ### ### ### ### ### ### ### ### ### ### }

      if pElement^.GID = Element then begin
         Result := i;
         exit;
      end;
   end;


end;

function TCollectionGIDtoSTR.Add_Update(Element: TGIDtoSTR): PGIDtoSTR;
var i : integer;
begin
     
     Result := nil;
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     i := Get_Index(Element.GID);        {### Neccessite adpation en fonction du type record  ### }
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     if i < 0 then begin 
        // L'élément n'existe pas, l'ajoute
        Result  := Add(Element);
     end else begin
        // L'élément existe déjà, le met à jour
        Result  := Items[i];     // Obtient le pointeur
        Result^ := Element;
     end;
     
end;




function TCollectionGIDtoSTR.Get_Item(Index: integer): TGIDtoSTR;
var pElement: PGIDtoSTR;
begin

     if Index < 0 then exit;
     if Index >= Count then exit;

     pElement := Items[Index];     // Obtient le pointeur
     Result := pElement^;

end;

function TCollectionGIDtoSTR.Delete(Index: integer): boolean;
var pElement: PGIDtoSTR;
begin

    Result := false;

    if (Index < 0) or (Index >= Count) then
       // Hors limite
       exit;


    // Obtient le pointeur
    pElement := Items[Index];

    if pElement <> nil then
       // Libére la mémoire créée lors de l'ajout
       Dispose(pElement);

       
    // Supprime le pointeur de la liste
    inherited Delete(Index);

    // Met le resultat à True
    Result := true;

end;


function TCollectionGIDtoSTR.Add(Element: TGIDtoSTR): PGIDtoSTR;
var pElement: PGIDtoSTR;
begin
    
    Result := nil;
    
    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Fait pointer l'élément
    
    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
    except
       Result := nil;
    end;
    
    // Pour libérer la mémoire occupé par l'élément pointer:  Dispose(pElement);

end;

// Simple ajout de pointeur
procedure TCollectionGIDtoSTR.SimpleAdd(Pointeur: PGIDtoSTR);
begin
    
    inherited Add(Pointeur);  // Ajoute le pointeur à la liste
    
end;

function TCollectionGIDtoSTR.GetItemx(Index: integer): TGIDtoSTR;
var pElement: PGIDtoSTR;
begin

   if Count < 0 then exit;
   if Index >= Count then exit;

   pElement := Items[Index];
   Result := pElement^;

end;



end.
